#include "servlet.h"
#include <fnmatch.h>

namespace sylar{
namespace http{

FunctionServlet::FunctionServlet(callback cb)
	:Servlet("FunctionalServlet")
	,m_cb(cb){
}

int32_t FunctionServlet::handle(sylar::http::HttpRequest::ptr request, sylar::http::HttpResponse::ptr response, sylar::http::HttpSession::ptr session){
	return m_cb(request, response, session);
}

ServletDispatch::ServletDispatch()
	:Servlet("ServletDispatch"){
	m_default.reset(new NotFoundServlet());
}
int32_t ServletDispatch::handle(sylar::http::HttpRequest::ptr request, sylar::http::HttpResponse::ptr response, sylar::http::HttpSession::ptr session){
	auto slt = getMatchedServlet(request->getPath());
	if(slt){
		slt->handle(request, response, session);
	}
	return 0;
}

void ServletDispatch::addServlet(const std::string& uri, Servlet::ptr slt){
	RWMutexType::WriteLock lock(m_mutex);
	m_datas[uri] = slt;
}
void ServletDispatch::addServlet(const std::string& uri, FunctionServlet::callback cb){
	RWMutexType::WriteLock lock(m_mutex);
	m_datas[uri].reset(new FunctionServlet(cb));
}
void ServletDispatch::addGlobServlet(const std::string& uri,  Servlet::ptr slt){
	RWMutexType::WriteLock lock(m_mutex);
	for(auto it = m_globs.begin(); it != m_globs.end();++it){
		if(it->first == uri){
			m_globs.erase(it);
			break;
		}
	}
	m_globs.push_back(std::make_pair(uri, slt));
}
void ServletDispatch::addGlobServlet(const std::string& uri, FunctionServlet::callback cb){
	return addGlobServlet(uri, FunctionServlet::ptr(new FunctionServlet(cb)));
}

void ServletDispatch::delServlet(const std::string& uri){
	RWMutexType::WriteLock lock(m_mutex);
	m_datas.erase(uri);
}
void ServletDispatch::delGlobServlet(const std::string& uri){
	RWMutexType::WriteLock lock(m_mutex);
	for(auto it = m_globs.begin(); it != m_globs.end();++it){
		if(it->first == uri){
			m_globs.erase(it);
			break;
		}
	}
}

Servlet::ptr ServletDispatch::getServlet(const std::string& uri){
	RWMutexType::WriteLock lock(m_mutex);
	auto it = m_datas.find(uri);
	return it == m_datas.end() ? nullptr : it->second;
}
Servlet::ptr ServletDispatch::getGlobServlet(const std::string& uri){
	RWMutexType::WriteLock lock(m_mutex);
	for(auto it = m_globs.begin();it != m_globs.end();++it){
		if(it->first == uri){
			return it->second;
		}
	}
	return nullptr;
}

Servlet::ptr ServletDispatch::getMatchedServlet(const std::string& uri){
	RWMutexType::WriteLock lock(m_mutex);
	auto mit = m_datas.find(uri);
	if(mit != m_datas.end()) 
		return mit->second;
	for(auto it = m_globs.begin();it != m_globs.end();++it){
		if(!fnmatch(it->first.c_str(), uri.c_str(), 0)){
			return it->second;
		}
	}
	return m_default;
}

NotFoundServlet::NotFoundServlet()
	:Servlet("NotFountServlet"){
}

int32_t NotFoundServlet::handle(sylar::http::HttpRequest::ptr request, sylar::http::HttpResponse::ptr response, sylar::http::HttpSession::ptr session){
	static const std::string&  RSP_BODY= "<html><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\"><title>页面未找到</title><style>body {max-width: 100%;margin: 0 30px 0 10%;overflow: hidden;font-family: \"Microsoft Yahei Light\",\"Microsoft Yahei\",PingFangSC-Regular,Helvetica,sans-serif,\"等线\";cursor: default;-webkit-tap-highlight-color: transparent;-webkit-user-select: none;user-select: none;}h1 {padding-top: 150px;margin: 0;color: #70C000;font-family: \"Microsoft Yahei\",PingFangSC-Regular,Helvetica,sans-serif,\"等线\";font-weight: bold;font-size: 135px;line-height: 110px;}h2 {font-size: 20px;}p {color: rgba(0,0,0,.6);font-size: small;}.link {color: #70C000;text-decoration: none;transition: all .25s;}.link:hover, #btnHome:hover {opacity: .8;}.link:active {filter: brightness(.8);}#btnHome {position: relative;top: 50px;padding: 8px 30px;background-color: #70C000;border-radius: 3px;color: white;font-size: small;text-decoration: none;transition: all .25s;}#btnHome:active {opacity: .6;}footer {position: fixed;bottom: 50px;color: rgba(0,0,0,.6);font-size: small;}</style></head><body><h1>404</h1><h2>Oops... 页面未找到</h2><p>很抱歉，您访问的页面资源不存在。请您确认网址无误后重试。</p><script>oncontextmenu = function() {return false;};</script></body></html>";
	response->setStatus(sylar::http::HttpStatus::NOT_FOUND);
	response->setHeader("Server", "sylar/1.0.0");
	response->setHeader("Content-Type", "text/html");
	response->setBody(RSP_BODY);
	return 0;
}

}
}